package se.webbzon.oschi01.tools.mapper;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Observable;
import java.util.Set;

import se.webbzon.oschi01.item.ItemEntry;
import se.webbzon.oschi01.item.ItemSet;
import se.webbzon.oschi01.utils.Pair;

public class MapperModel extends Observable {
	
	private final ItemSet newItems;
	
	private Set<ItemEntry> unmappedItems;
	
	private Map<ItemEntry,ItemEntry> mappedItems;
	
	public MapperModel(ItemSet oldItems, ItemSet newItems) {
		this.newItems = newItems;
		unmappedItems = new HashSet<ItemEntry>(oldItems);
		mappedItems = new HashMap<ItemEntry,ItemEntry>();
	}
	
	public boolean mapItem(ItemEntry oldItem, ItemEntry newItem) {
		if (newItems.contains(newItem) && unmappedItems.remove(oldItem)) {
			Pair<ItemEntry,ItemEntry> p = new Pair<ItemEntry,ItemEntry>(oldItem,newItem);
			mappedItems.put(oldItem,newItem);
			setChanged();
			notifyObservers(new MapperEvent(this,MapperEvent.Action.MAPPING_ADDED,p));
			return true;
		} else
			return false;
	}
	
	public boolean mapItems(Map<ItemEntry,ItemEntry> items) {
		boolean changed = false;
		for (Entry<ItemEntry,ItemEntry> e : items.entrySet()) {
			if (newItems.contains(e.getValue()) && unmappedItems.remove(e.getKey())) {
				changed = true;
				mappedItems.put(e.getKey(),e.getValue());
			}
		}
		if (changed) {
			setChanged();
			notifyObservers(new MapperEvent(this,MapperEvent.Action.MAPPING_CHANGED,null));
			return true;
		} else
			return false;
	}
	
	public void clearMappings() {
		for (ItemEntry oldItem : mappedItems.keySet()) {
			unmappedItems.add(oldItem);
		}
		mappedItems.clear();
		setChanged();
		notifyObservers(new MapperEvent(this,MapperEvent.Action.MAPPING_CHANGED,null));
	}
	
	public boolean removeMapping(ItemEntry oldItem) {
		ItemEntry newItem = mappedItems.remove(oldItem);
		if (newItem != null) {
			Pair<ItemEntry,ItemEntry> p = new Pair<ItemEntry,ItemEntry>(oldItem,newItem);
			unmappedItems.add(oldItem);
			setChanged();
			notifyObservers(new MapperEvent(this,MapperEvent.Action.MAPPING_REMOVED,p));
			return true;
		} else
			return false;
	}
	
	public boolean removeMappings(Collection<ItemEntry> items) {
		boolean changed = false;
		for (ItemEntry item : items) {
			if (mappedItems.remove(item) != null) {
				unmappedItems.add(item);
				changed = true;
			}
		}
		if (changed) {
			setChanged();
			notifyObservers(new MapperEvent(this,MapperEvent.Action.MAPPING_CHANGED,null));
			return true;
		} else
			return false;
	}
	
	public boolean isMapped(ItemEntry oldItem) {
		return mappedItems.containsKey(oldItem);
	}
	
	public ItemEntry getMapping(ItemEntry oldItem) {
		return mappedItems.get(oldItem);
	}
	
	public Map<ItemEntry,ItemEntry> getMappings() {
		return Collections.unmodifiableMap(mappedItems);
	}
	
	public Set<ItemEntry> getUnmappedItems() {
		return Collections.unmodifiableSet(unmappedItems);
	}
	
	public ItemSet getAvailableItems() {
		return newItems;
	}

}
